/*******************************************************************************
 * -------
 *   Copyright 2011 @ Fluid India Consultancy
 *   All Rights Reserved
 * -------
 ******************************************************************************/
package org.fluidindia.core.dao;

import java.sql.ResultSet;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;

import com.kapil.framework.exception.impl.ConfigurationException;
import com.kapil.framework.reader.IMessageReader;
import com.kapil.framework.reader.MessageReaderFactory;

/**
 * <p>
 * This is a base and Abstract Data Access Object, that holds common capabilities which are required across various Data
 * Access objects
 * </p>
 * 
 * <p>
 * Given this is an Abstract class, you can not create objects for this class; you need to create you back-end specific
 * data access objects and extend from this class.
 * </p>
 * 
 * <p>
 * This Data Access Object uses {@link SimpleJdbcTemplate} to connect to the database. Using Spring Configuration you
 * need to inject a dataSource to make this work.
 * </p>
 * 
 * @author Kapil Viren Ahuja
 * 
 * @param <V>
 */
@SuppressWarnings("rawtypes")
public abstract class AbstractDao<V>
{
    private SimpleJdbcTemplate jdbcTemplate;

    public String              sqlCommandConfigurationFile;

    private IMessageReader     configReader;


    /**
     * Set the DataSource to the {@link SimpleJdbcTemplate}
     * 
     * 
     * @param dataSource - object of {@link DataSource} to which this DAO needs to connect to.
     * 
     */
    public void setDataSource(DataSource dataSource)
    {
        this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }


    /**
     * Sets the name of the XML file at the root of the classpath from where the queries should be picked up
     * 
     * @param sqlCommandConfigurationFile
     */
    public void setSqlCommandConfigurationFile(String sqlCommandConfigurationFile)
    {
        this.sqlCommandConfigurationFile = sqlCommandConfigurationFile;
        configReader = MessageReaderFactory.getInstance().getXmlConfigurationReader(sqlCommandConfigurationFile);
    }


    /**
     * Responsible for fetching a SQL Query from an underlying XML
     * Configuration file based on the parameters that the concrete implementation will provide.
     * 
     * @param tableName - A {@link String} that represents name of the table as defined in the XML Configuration File
     * @param functionName - A {@link String} with the name of the function as defined in the XML Configuration File
     * 
     * @return - A {@link String} containing the SQL query or an {@link ConfigurationException} if no query if located.
     * 
     */
    protected String getQuery(String tableName, String functionName)
    {
        String param = "admin." + tableName + "." + functionName;
        String query = configReader.getMessage(param);
        
        if(query == null)
        {
            throw new ConfigurationException(ConfigurationException.INVALID_CONFIGURATION, new String[]{param});
        }
        else
        {
            return query;
        }
    }


    
    /**
     * Responsible for running a SQL Query on a table using the {@link SimpleJdbcTemplate}.
     * 
     * </br>
     * 
     * This method will also convert the {@link ResultSet} into a Java Object using the Mappers.
     * 
     * 
     * @param tableName - A {@link String} that represents name of the table as defined in the XML Configuration File
     * @param functionName - A {@link String} with the name of the function as defined in the XML Configuration File
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<V> query(String sql, RowMapper mapper, Object... args)
    {
        return this.jdbcTemplate.query(sql, mapper, args);
    }
}
